#ifndef _ODBC_H_
#define _ODBC_H_

#include <time.h>

#include <functional>
#include <databaselib/io/DataType.h>
#include <databaselib/io/Database.h>
#include <utillib/stl/QueueList.h>

#pragma comment ( lib, "ODBC32.lib" )

#ifdef _DEBUG
#pragma comment ( lib, "DataBaseD.lib" )
#else
#pragma comment ( lib, "DataBase.lib" )
#endif


#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <utillib/util/Synchronized.h>

/*
	DBMS Contol By ODBC Class
*/
namespace databaselib
{
	namespace io
	{
		class AgentODBC;
		class ODBC : public Database
		{
		public:
			ODBC( AgentODBC *parentDB );
			virtual ~ODBC();

			bool isConnect()
			{
				if ( m_stmt != SQL_NULL_HANDLE ) return ( true );
				return ( false );
			};
			bool prepare( const char * );

			virtual bool connect();
			virtual bool execute();

			virtual bool executeSQL( const char * );
			virtual bool fetch( void );

			void endFetch();

			void close( void );

			int getColumnID( char *,char *);
			int getColumnType( SQLUSMALLINT );
			bool getColumnName( SQLUSMALLINT , char *);

			bool bindParameter( BYTE order, BYTE inout, BYTE cType, BYTE sqlType,  void *value, int valueLength , DWORD columnSize = 0, BYTE degit = 0 );

			template < class _OutType >
			bool getData( _OutType &out, SQLSMALLINT type )
			{
				if ( m_isFetch == true )
				{
					SQLRETURN sqlRet;
					m_columnNo++;
					sqlRet = SQLGetData( m_stmt, m_columnNo, type, &out, sizeof( _OutType ), 0 );
					if ( sqlOK( sqlRet ) == true ) return ( true );
					out = 0;
				}
				return ( false );
			};

			virtual ODBC& operator >> ( char &out )
			{
				getData( out, SQL_C_STINYINT );
				return *this;
			};
			virtual Database& operator >> ( bool &out )
			{
				out = false;
				return *this;
			}

			virtual ODBC& operator >> ( short &out )
			{
				getData( out, SQL_C_SHORT );
				return *this;
			};

			virtual ODBC& operator >> ( unsigned int &out )
			{
				getData( out, SQL_C_ULONG );
				return *this;
			};

			virtual ODBC& operator >> ( int &out )
			{
				getData( out, SQL_C_SLONG );
				return *this;
			};

			virtual ODBC& operator >> ( float &out )
			{
				getData( out, SQL_C_FLOAT );
				return *this;
			};

			virtual ODBC& operator >> ( unsigned char &out )
			{
				getData( out, SQL_C_UTINYINT );
				return *this;
			};

			virtual ODBC& operator >> ( unsigned short &out )
			{
				getData( out, SQL_C_USHORT );
				return *this;
			};

			virtual ODBC& operator >> ( unsigned long &out )
			{
				getData( out, SQL_C_ULONG );
				return *this;
			};
			virtual ODBC& operator >> ( __int64 &out )
			{
				getData( out, SQL_C_UBIGINT );
				return *this;
			};

			virtual ODBC& operator >> ( char *out )
			{
				if ( m_isFetch == true )
				{
					SQLRETURN sqlRet;
					int width;

					m_columnNo++;
					SQLColAttribute( m_stmt, m_columnNo, SQL_DESC_OCTET_LENGTH, 0, 0, 0, &width );
					sqlRet = SQLGetData( m_stmt, m_columnNo, SQL_C_CHAR, out, width, 0 );
					if ( sqlOK( sqlRet ) == false ) out[0] = '\0';
				}

				return *this;
			};

			virtual ODBC& operator >> ( struct tm &out )
			{
				if ( m_isFetch == true )
				{
					SQLRETURN sqlRet;
					m_columnNo++;
					sqlRet = SQLGetData( m_stmt, m_columnNo, SQL_C_TIMESTAMP, &out, sizeof( TIMESTAMP_STRUCT ), 0 );
				}
				return ( *this );
			};

			virtual ODBC& operator >> ( SmallDate &out )
			{
				if ( m_isFetch == true )
				{
					struct tm tm;
					SQLRETURN sqlRet;
					m_columnNo++;
					sqlRet = SQLGetData( m_stmt, m_columnNo, SQL_C_TIMESTAMP, &tm, sizeof( TIMESTAMP_STRUCT ), 0 );

					out.year = ( WORD )tm.tm_yday + 1900;
					out.mon = ( BYTE )tm.tm_mon + 1;
					out.day = ( BYTE )tm.tm_mday;
				}
				return ( *this );
			}
		private:
			void initialize( void );
			bool release();
			

			bool sqlOK( SQLRETURN result );
			bool trimRight(unsigned char *);

			bool m_isExecute;
			bool m_isFetch;
			SQLUSMALLINT m_columnNo;
			HENV m_env;
			HDBC m_dbc;
			HSTMT m_stmt;

			AgentODBC *m_parentAgentDB;
		};
		class AgentODBC	 : public AgentDB // DataBase(OLE DB) Control Class
		{
		public:
			AgentODBC();
			virtual ~AgentODBC();

		public:
			virtual bool initializeDataBaseEnv( char *dataBaseIP, char *defaultDB, char *userid, char *password );
			virtual bool releaseDataBaseEnv();

			char *getDBConnString()
			{
				return ( m_dbConnString );
			}

			virtual Database *getNewDBInstance();
			void setPort( int port )
			{
				m_port = port;
			};
			void setDSNName( char *name )
			{
				strcpy( m_dsnName, name );
			};

		protected:
			char *m_dbConnString;
			int m_port;
			char m_dsnName[ _MAX_PATH ];
		};
	}
}

#endif